package edu.amm.fanal.api;

import edu.amm.api.Bounds;

/**
 * Координатная система, образованная интегралами
 * от -1 до x от многочленов Лежандра.
 * 
 * @author Иванов Илья
 * @since 2013-05-12
 *
 */
public class IntegralLegendreCoordinates extends Coordinates {
	
	/**
	 * Создаёт экземпляр координатной системы.
	 */
	protected IntegralLegendreCoordinates() {
		super(Bounds.LEGENDRE_BOUNDS);
	}
	
	public String getName() {
		return getCoordinatesName();
	}
	
	protected Function[] coordinates(int count) {
		Function[] coordinates = new Function[count];
		
		for (int i = 0; i < coordinates.length; i++) {
			final int n = i + 1;
			
			coordinates[i] = new Function(BoundaryProblem.SOLUTION_DIM) {
				
				private Function firstDerivative = new Function(getDim()) {
					
					private Function secondDerivative = new Function(getDim()) {
						
						protected double getValue(double... x) {
							return D(n, x[0]);
						}
					};
					
					protected double getValue(double... x) {
						return P(n, x[0]);
					}
					
					protected Function getDerivative(int variableNumber) {
						return secondDerivative;
					}
				};
				
				protected double getValue(double... x) {
					return I(n, x[0]);
				}
				
				protected Function getDerivative(int variableNumber) {
					return firstDerivative;
				}
			};
		}
		
		return coordinates;
	}
	
	/**
	 * Интеграл от -1 до x от многочлена Лежандра.
	 */
	private double I(int n, double x) {
		double y;
		if (n == 0)
			y = x + 1;
		else
			y = (P(n + 1, x) - x * P(n, x)) / n;
		
		return y;
	}
	
	/**
	 * Многочлен Лежандра Pn(x).
	 */
	private double P(int n, double x) {
		double y;
		if (n == 0)
			y = 1;
		else if (n == 1)
			y = x;
		else
			y = ((double) (2 * n - 1) / n) * x * P(n - 1, x) - ((double) (n - 1) / n) * P(n - 2, x);
		
		return y;
	}
	
	/**
	 * Производная от многочлена Лежандра.
	 */
	private double D(int n, double x) {
		double y;
		if (n == 0)
			y = 0;
		else
			y = x * D(n - 1, x) + n * P(n - 1, x);
		
		return y;
	}
	
	public static String getCoordinatesName() {
		return "Интегр. от многочл. Леж.";
	}
}